'use strict'
import L from 'leaflet'
/* 绘制popup引导线
 使用示例：L.popup({popupmovable: true})
*/
const PopupMovable = L.Handler.extend({
  constructor(map) {
    if (this._map === undefined) {
      this._map = map
    }
  },
  //This is class name of popup element for judging whether popup moved or not.
  _movedLabel: 'popup-moved',

  //Restore Popup's css(drawing popup's leader).
  _restorePopup(e) {
    const popup = e.popup || e
    if (!popup.grideline) return
    popup.grideline.remove()
  },

  _calcLatLngs(p) {
    const p1 = this._map.latLngToLayerPoint(p.originalLatlng)
    const rect = p._container.getBoundingClientRect()
    const cp = this._map.latLngToLayerPoint(p.getLatLng())
    if (p.options.offset) {
      cp.x = cp.x + p.options.offset.x
      cp.y = cp.y + p.options.offset.y
    }
    const xL = cp.x - rect.width / 2
    const yT = cp.y - rect.height
    const xR = cp.x + rect.width / 2
    const yB = cp.y
    const xC = cp.x
    const yC = cp.y - rect.height / 2
    const p2 = { x: xC, y: yC }
    if (p1.x > xR && p1.y < yB && p1.y > yT) {
      p2.x = xR
    }
    if (p1.x < xL && p1.y < yB && p1.y > yT) {
      p2.x = xL
    }
    if (p1.y < yT && p1.x > xL && p1.x < xR) {
      p2.y = yT
    }
    if (p1.y > yB && p1.x > xL && p1.x < xR) {
      p2.y = yB
    }
    const p3 = {
      x: p1.x + (p2.x - p1.x) / 2,
      y: p1.y,
    }
    if (p2.y === yC && p2.x !== xC) {
      p3.y = p2.y
    }
    return [p.originalLatlng, this._map.layerPointToLatLng(p3), this._map.layerPointToLatLng(p2)]
  },
  _drawGrideline(p) {
    const latlngs = this._calcLatLngs(p)
    if (p.grideline) {
      p.grideline.setLatLngs(latlngs)
      return
    }
    p.grideline = L.polyline(latlngs, { color: 'rgba(161, 183, 203, 0.5)', weight: 2 }).addTo(
      this._map
    )
  },

  /*
  Main Function
  */
  _popupMovable(mk) {
    const p = mk.popup
    if (!p.options.popupmovable) return
    //First, Embed the original position in Popup's Object.(to be used later.)
    p.originalLatlng = p.getLatLng()
    //Enbed the marker option(popupAnchor) that bindding this popup.
    try {
      p._wrapper.parentNode.popupAnchor = p._source.options.icon.options.popupAnchor
    } catch {
      p._wrapper.parentNode.popupAnchor = [0, 0]
    }
    //Make Popup elements movable.
    const dragPopup = new L.Draggable(p._container, p._wrapper)
    const _el = dragPopup._element
    // this._drawCss(_el, _el._leaflet_pos)
    p.setLatLng(this._map.layerPointToLatLng(_el._leaflet_pos))
    L.DomUtil.addClass(_el, this._movedLabel)
    this._drawGrideline(p)
    dragPopup
      .on('drag', (e) => {
        p.setLatLng(this._map.layerPointToLatLng(e.target._newPos))
        this._drawGrideline(p)
        // this._drawCss(e.target._element,e.target._newPos);
      })
      .enable()
    if (p.options.isDrag === false) dragPopup.disable()
    //When binded Marker clicked, restore leadline.
    if (p._source !== undefined) {
      L.featureGroup([p._source]).on('click', () => this._restorePopup(p))
    }
  },

  _zoomEvent() {
    this._map.eachLayer((layer) => {
      if (layer instanceof L.Popup && layer.grideline) {
        this._drawGrideline(layer)
      }
    })
  },

  addHooks: function () {
    this._map.on('popupopen', (e) => this._popupMovable(e), this)
    this._map.on('popupclose', (e) => this._restorePopup(e), this)
    this._map.on('zoom', (e) => this._zoomEvent(), this)
  },

  removeHooks: function () {
    this._map.off('popupopen', (e) => this._popupMovable(e), this)
    this._map.off('popupclose', (e) => this._restorePopup(e), this)
    this._map.off('zoomstart', (e) => this._zoomEvent(), this)
  },
})

L.Map.mergeOptions({
  popupMovable: false,
})

L.Map.addInitHook(function () {
  this.popupMovable = new PopupMovable(this)
  this.popupMovable.enable()
})
